/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   gbx-emu - debuggerwidget.cpp                                          *
 *   gbx-emu homepage: http://code.google.com/p/gbx-emu/                   *
 *   Copyright (C) 2009 olejl77@gmail.com                                  *
 *                                                                         *
 *   This program is free software: you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "debuggerwidget.h"
#include "ui_debuggerwidget.h"
#include "disasmmodel.h"
#include "registermodel.h"
#include "mainwindow.h"
#include "../core/cpu.h"
#include "../core/memory.h"
#include "breakpointswidget.h"
#include <QMessageBox>
#include <QHeaderView>

DebuggerWidget::DebuggerWidget(MainWindow *m, QWidget *parent) : QWidget(parent), ui(new Ui::DebuggerWidgetClass)
{
    main = m;
    _gb = NULL;
    _cpu = NULL;
    _mem = NULL;
    _dbg = NULL;
    ui->setupUi(this);

    oplist
        << "NOP -/-"    << "LD BC,nn"  << "LD (BC),A"  << "INC BC"    << "INC B"      << "DEC B"     << "LD B,n"     << "RLCA -/-"  // 0x00 - 0x07
        << "LD (nn),SP" << "ADD HL,BC" << "LD A,(BC)"  << "DEC BC"    << "INC C"      << "DEC C"     << "LD C,n"     << "RRCA -/-"  // 0x08 - 0x0f
        << "STOP -/-"   << "LD DE,nn"  << "LD (DE),A"  << "INC DE"    << "INC D"      << "DEC D"     << "LD D,n"     << "RLA -/-"   // 0x10 - 0x17
        << "JR n"       << "ADD HL,DE" << "LD A,(DE)"  << "DEC DE"    << "INC E"      << "DEC E"     << "LD E,n"     << "RRA -/-"   // 0x18 - 0x1f
        << "JR NZ,*"    << "LD HL,nn"  << "LDI (HL),A" << "INC HL"    << "INC H"      << "DEC H"     << "LD H,n"     << "DAA -/-"   // 0x20 - 0x27
        << "JR Z,*"     << "ADD HL,HL" << "LDI A,(HL)" << "DEC HL"    << "INC L"      << "DEC L"     << "LD L,n"     << "CPL -/-"   // 0x28 - 0x2f
        << "JR NC,*"    << "LD SP,nn"  << "LDD (HL),A" << "INC SP"    << "INC (HL)"   << "DEC (HL)"  << "LD (HL),n"  << "SCF -/-"   // 0x30 - 0x37
        << "JR C,*"     << "ADD HL,SP" << "LD A,(HLD)" << "DEC SP"    << "INC A"      << "DEC A"     << "LD A,#"     << "CCF -/-"   // 0x38 - 0x3f
        << "LD B,B"     << "LD B,C"    << "LD B,D"     << "LD B,E"    << "LD B,H"     << "LD B,L"    << "LD B,(HL)"  << "LD B,A"    // 0x40 - 0x47
        << "LD C,B"     << "LD C,C"    << "LD C,D"     << "LD C,E"    << "LD C,H"     << "LD C,L"    << "LD C,(HL)"  << "LD C,A"    // 0x48 - 0x4f
        << "LD D,B"     << "LD D,C"    << "LD D,D"     << "LD D,E"    << "LD D,H"     << "LD D,L"    << "LD D,(HL)"  << "LD D,A"    // 0x50 - 0x57
        << "LD E,B"     << "LD E,C"    << "LD E,D"     << "LD E,E"    << "LD E,H"     << "LD E,L"    << "LD E,(HL)"  << "LD E,A"    // 0x58 - 0x5f
        << "LD H,B"     << "LD H,C"    << "LD H,D"     << "LD H,E"    << "LD H,H"     << "LD H,L"    << "LD H,(HL)"  << "LD H,A"    // 0x60 - 0x67
        << "LD L,B"     << "LD L,C"    << "LD L,D"     << "LD L,E"    << "LD L,H"     << "LD L,L"    << "LD L,(HL)"  << "LD L,A"    // 0x68 - 0x6f
        << "LD (HL),B"  << "LD (HL),C" << "LD (HL),D"  << "LD (HL),E" << "LD (HL),H"  << "LD (HL),L" << "HALT -/-"   << "LD (HL),A" // 0x70 - 0x77
        << "LD A,B"     << "LD A,C"    << "LD A,D"     << "LD A,E"    << "LD A,H"     << "LD A,L"    << "LD A,(HL)"  << "LD A,A"    // 0x78 - 0x7f
        << "ADD A,B"    << "ADD A,C"   << "ADD A,D"    << "ADD A,E"   << "ADD A,H"    << "ADD A,L"   << "ADD A,(HL)" << "ADD A,A"   // 0x80 - 0x87
        << "ADC A,B"    << "ADC A,C"   << "ADC A,D"    << "ADC A,E"   << "ADC A,H"    << "ADC A,L"   << "ADC A,(HL)" << "ADC A,A"   // 0x88 - 0x8f
        << "SUB B"      << "SUB C"     << "SUB D"      << "SUB E"     << "SUB H"      << "SUB L"     << "SUB (HL)"   << "SUB A"     // 0x90 - 0x97
        << "SBC A,B"    << "SBC A,C"   << "SBC A,D"    << "SBC A,E"   << "SBC A,H"    << "SBC A,L"   << "SBC A,(HL)" << "SBC A,A"   // 0x98 - 0x9f
        << "AND B"      << "AND C"     << "AND D"      << "AND E"     << "AND H"      << "AND L"     << "AND (HL)"   << "AND A"     // 0xa0 - 0xa7
        << "XOR B"      << "XOR C"     << "XOR D"      << "XOR E"     << "XOR H"      << "XOR L"     << "XOR (HL)"   << "XOR A"     // 0xa8 - 0xaf
        << "OR B"       << "OR C"      << "OR D"       << "OR E"      << "OR H"       << "OR L"      << "OR (HL)"    << "OR A"      // 0xb0 - 0xb7
        << "CP B"       << "CP C"      << "CP D"       << "CP E"      << "CP H"       << "CP L"      << "CP (HL)"    << "CP A"      // 0xb8 - 0xbf
        << "RET NZ"     << "POP BC"    << "JP NZ,nn"   << "JP nn"     << "CALL NZ,nn" << "PUSH BC"   << "ADD A,#"    << "RST 00H"   // 0xc0 - 0xc7
        << "RET Z"      << "RET -/-"   << "JP Z,nn"    << ""          << "CALL Z,nn"  << "CALL nn"   << "ADC A,#"    << "RST 08H"   // 0xc8 - 0xcf
        << "RET NC"     << "POP DE"    << "JP NC,nn"   << ""          << "CALL NC,nn" << "PUSH DE"   << "SUB A,#"    << "RST 10H"   // 0xd0 - 0xd7
        << "RET C"      << "RETI -/-"  << "JP C,nn"    << ""          << "CALL C,nn"  << ""          << "SBC A,#"    << "RST 18H"   // 0xd8 - 0xdf
        << "LD ($FF00+n),A" << "POP HL" << "LD ($FF00+C),A" << ""     << ""           << "PUSH HL"   << "AND #"      << "RST 20H"   // 0xe0 - 0xe7
        << "ADD SP,#"   << "JP (HL)"   << "LD (nn),A"  << ""          << ""           << ""          << "XOR *"      << "RST 28H"   // 0xe8 - 0xef
        << "LD A,($FF00+n)" << "POP AF" << "LD A,(C)"  << "DI -/-"    << ""           << "PUSH AF"   << "OR #"       << "RST 30H"   // 0xf0 - 0xf7
        << "LDHL SP,n"  << "LD SP,HL"  << "LD A,(nn)"  << "EI -/-"    << ""           << ""          << "CP #"       << "RST 38H";  // 0xf8 - 0xff

    oplist_cb
        << "RLC B"   << "RLC C"   << "RLC D"   << "RLC E"   << "RLC H"   << "RLC L"   << "RLC (HL)"   << "RLC A"   // 0x00 - 0x07
        << "RRC B"   << "RRC C"   << "RRC D"   << "RRC E"   << "RRC H"   << "RRC L"   << "RRC (HL)"   << "RRC A"   // 0x08 - 0x0f
        << "RL B"    << "RL C"    << "RL D"    << "RL E"    << "RL H"    << "RL L"    << "RL (HL)"    << "RL A"    // 0x10 - 0x17
        << "RR B"    << "RR C"    << "RR D"    << "RR E"    << "RR H"    << "RR L"    << "RR (HL)"    << "RR A"    // 0x18 - 0x1f
        << "SLA B"   << "SLA C"   << "SLA D"   << "SLA E"   << "SLA H"   << "SLA L"   << "SLA (HL)"   << "SLA A"   // 0x20 - 0x27
        << "SRA B"   << "SRA C"   << "SRA D"   << "SRA E"   << "SRA H"   << "SRA L"   << "SRA (HL)"   << "SRA A"   // 0x28 - 0x2f
        << "SWAP B"  << "SWAP C"  << "SWAP D"  << "SWAP E"  << "SWAP H"  << "SWAP L"  << "SWAP (HL)"  << "SWAP A"  // 0x30 - 0x37
        << "SRL B"   << "SRL C"   << "SRL D"   << "SRL E"   << "SRL H"   << "SRL L"   << "SRL (HL)"   << "SRL A"   // 0x38 - 0x3f
        << "BIT 0,B" << "BIT 0,C" << "BIT 0,D" << "BIT 0,E" << "BIT 0,H" << "BIT 0,L" << "BIT 0,(HL)" << "BIT 0,A" // 0x40 - 0x47
        << "BIT 1,B" << "BIT 1,C" << "BIT 1,D" << "BIT 1,E" << "BIT 1,H" << "BIT 1,L" << "BIT 1,(HL)" << "BIT 1,A" // 0x48 - 0x4f
        << "BIT 2,B" << "BIT 2,C" << "BIT 2,D" << "BIT 2,E" << "BIT 2,H" << "BIT 2,L" << "BIT 2,(HL)" << "BIT 2,A" // 0x50 - 0x57
        << "BIT 3,B" << "BIT 3,C" << "BIT 3,D" << "BIT 3,E" << "BIT 3,H" << "BIT 3,L" << "BIT 3,(HL)" << "BIT 3,A" // 0x58 - 0x5f
        << "BIT 4,B" << "BIT 4,C" << "BIT 4,D" << "BIT 4,E" << "BIT 4,H" << "BIT 4,L" << "BIT 4,(HL)" << "BIT 4,A" // 0x60 - 0x67
        << "BIT 5,B" << "BIT 5,C" << "BIT 5,D" << "BIT 5,E" << "BIT 5,H" << "BIT 5,L" << "BIT 5,(HL)" << "BIT 5,A" // 0x68 - 0x6f
        << "BIT 6,B" << "BIT 6,C" << "BIT 6,D" << "BIT 6,E" << "BIT 6,H" << "BIT 6,L" << "BIT 6,(HL)" << "BIT 6,A" // 0x70 - 0x77
        << "BIT 7,B" << "BIT 7,C" << "BIT 7,D" << "BIT 7,E" << "BIT 7,H" << "BIT 7,L" << "BIT 7,(HL)" << "BIT 7,A" // 0x78 - 0x7f
        << "RES 0,B" << "RES 0,C" << "RES 0,D" << "RES 0,E" << "RES 0,H" << "RES 0,L" << "RES 0,(HL)" << "RES 0,A" // 0x80 - 0x87
        << "RES 1,B" << "RES 1,C" << "RES 1,D" << "RES 1,E" << "RES 1,H" << "RES 1,L" << "RES 1,(HL)" << "RES 1,A" // 0x88 - 0x8f
        << "RES 2,B" << "RES 2,C" << "RES 2,D" << "RES 2,E" << "RES 2,H" << "RES 2,L" << "RES 2,(HL)" << "RES 2,A" // 0x90 - 0x97
        << "RES 3,B" << "RES 3,C" << "RES 3,D" << "RES 3,E" << "RES 3,H" << "RES 3,L" << "RES 3,(HL)" << "RES 3,A" // 0x98 - 0x9f
        << "RES 4,B" << "RES 4,C" << "RES 4,D" << "RES 4,E" << "RES 4,H" << "RES 4,L" << "RES 4,(HL)" << "RES 4,A" // 0xa0 - 0xa7
        << "RES 5,B" << "RES 5,C" << "RES 5,D" << "RES 5,E" << "RES 5,H" << "RES 5,L" << "RES 5,(HL)" << "RES 5,A" // 0xa8 - 0xaf
        << "RES 6,B" << "RES 6,C" << "RES 6,D" << "RES 6,E" << "RES 6,H" << "RES 6,L" << "RES 6,(HL)" << "RES 6,A" // 0xb0 - 0xb7
        << "RES 7,B" << "RES 7,C" << "RES 7,D" << "RES 7,E" << "RES 7,H" << "RES 7,L" << "RES 7,(HL)" << "RES 7,A" // 0xb8 - 0xbf
        << "SET 0,B" << "SET 0,C" << "SET 0,D" << "SET 0,E" << "SET 0,H" << "SET 0,L" << "SET 0,(HL)" << "SET 0,A" // 0xc0 - 0xc7
        << "SET 1,B" << "SET 1,C" << "SET 1,D" << "SET 1,E" << "SET 1,H" << "SET 1,L" << "SET 1,(HL)" << "SET 1,A" // 0xc8 - 0xcf
        << "SET 2,B" << "SET 2,C" << "SET 2,D" << "SET 2,E" << "SET 2,H" << "SET 2,L" << "SET 2,(HL)" << "SET 2,A" // 0xd0 - 0xd7
        << "SET 3,B" << "SET 3,C" << "SET 3,D" << "SET 3,E" << "SET 3,H" << "SET 3,L" << "SET 3,(HL)" << "SET 3,A" // 0xd8 - 0xdf
        << "SET 4,B" << "SET 4,C" << "SET 4,D" << "SET 4,E" << "SET 4,H" << "SET 4,L" << "SET 4,(HL)" << "SET 4,A" // 0xe0 - 0xe7
        << "SET 5,B" << "SET 5,C" << "SET 5,D" << "SET 5,E" << "SET 5,H" << "SET 5,L" << "SET 5,(HL)" << "SET 5,A" // 0xe8 - 0xef
        << "SET 6,B" << "SET 6,C" << "SET 6,D" << "SET 6,E" << "SET 6,H" << "SET 6,L" << "SET 6,(HL)" << "SET 6,A" // 0xf0 - 0xf7
        << "SET 7,B" << "SET 7,C" << "SET 7,D" << "SET 7,E" << "SET 7,H" << "SET 7,L" << "SET 7,(HL)" << "SET 7,A" // 0xf8 - 0xff
        ;

    qRegisterMetaType<QItemSelection>("QItemSelection");
    smDebugger = new QSignalMapper(this);
    connect(ui->pushStep, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushNext, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushRun, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushTrace, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushBreak, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushReset, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushNewBP, SIGNAL(clicked()), smDebugger, SLOT(map()));
    connect(ui->pushToggleBP, SIGNAL(clicked()), smDebugger, SLOT(map()));
    smDebugger->setMapping(ui->pushStep, "Step");
    smDebugger->setMapping(ui->pushNext, "Next");
    smDebugger->setMapping(ui->pushRun, "Run");
    smDebugger->setMapping(ui->pushTrace, "Trace");
    smDebugger->setMapping(ui->pushBreak, "Break");
    smDebugger->setMapping(ui->pushReset, "Reset");
    smDebugger->setMapping(ui->pushNewBP, "NewBP");
    smDebugger->setMapping(ui->pushToggleBP, "ToggleBP");
    connect(smDebugger, SIGNAL(mapped(const QString &)), this, SLOT(clicked(const QString &)));

    io = new u8[0x4c];
    oam = new u8[0xa0];
}

DebuggerWidget::~DebuggerWidget()
{
    delete ui;
    delete io;
    io = NULL;
    _gb = NULL;
    _cpu = NULL;
    _mem = NULL;
    _dbg = NULL;
}

void DebuggerWidget::initDebugger()
{
    u8 *cart = _gb->getCart();
    u32 size = _gb->getCartSize();

    for (u32 i = 0; i < size; i++) {
        QString arg, str;

        if (cart[i] == 0xcb) {
            pcs << QString("0x%1").arg(i, 4, 16, QChar('0'));
            i++;
            str = oplist_cb.at(cart[i]);
        } else {
            str = oplist.at(cart[i]);
            pcs << QString("0x%1").arg(i, 4, 16, QChar('0'));
        }
        opcodes << str;
        if (str.indexOf("(nn)") > 0) {
            u32 addr = (cart[i + 2] << 8) + cart[i + 1];
            arg = QString("(nn) = 0x%1").arg(cart[addr], 2, 16, QChar('0'));
            i += 2;
        } else if (str.indexOf("nn") > 0) {
            u32 addr = (cart[i + 2] << 8) + cart[i + 1];
            arg = QString("nn = 0x%1").arg(addr, 4, 16, QChar('0'));
            i += 2;
        } else if (str.indexOf("*") > 0) {
            i++;
            arg = QString("* = 0x%1").arg(cart[i], 2, 16, QChar('0'));
        } else if (str.indexOf("n") > 0) {
            i++;
            arg = QString("n = 0x%1").arg(cart[i], 2, 16, QChar('0'));
        } else if (str.indexOf("#") > 0) {
            i++;
            arg = QString("# = 0x%1").arg(cart[i], 2, 16, QChar('0'));
        } else {
            arg = "";
        }
        args << arg;
    }
    modelDisasm = new DisasmModel();
    modelDisasm->setArgList(args);
    modelDisasm->setPcList(pcs);
    modelDisasm->setMnemonicList(opcodes);
    ui->tableView->verticalHeader()->setDefaultSectionSize(rowHeight); //setHeight
    ui->tableView->setModel(modelDisasm);
    ui->tableView->horizontalHeader()->hide();
    ui->tableView->verticalHeader()->hide();
    ui->tableView->horizontalHeader()->setStretchLastSection(true);
    ui->tableView->setColumnWidth(1, 120);

    // Registers
    mnemonicRegs << "A" << "BC" << "DE" << "HL" << "SP";
    modelRegs = new RegisterModel(mnemonicRegs, 4);
    ui->tableRegister->verticalHeader()->setDefaultSectionSize(rowHeight); //setHeight
    ui->tableRegister->setModel(modelRegs);
    ui->tableRegister->horizontalHeader()->hide();
    ui->tableRegister->verticalHeader()->hide();
    ui->tableRegister->resizeColumnsToContents();
    ui->tableRegister->horizontalHeader()->setStretchLastSection(true);
    A = 0x48;
    SP = 0x3456;
    BC = 0x3456;
    DE = 0x3456;
    HL = 0x3456;

    // Flags
    mnemonicFlags << "IME" << "Z" << "N" << "H" << "C";
    modelFlags = new RegisterModel(mnemonicFlags, 1);
    ui->tableFlag->verticalHeader()->setDefaultSectionSize(rowHeight); //setHeight
    ui->tableFlag->setModel(modelFlags);
    ui->tableFlag->horizontalHeader()->hide();
    ui->tableFlag->verticalHeader()->hide();
    ui->tableFlag->resizeColumnsToContents();
    ui->tableFlag->horizontalHeader()->setStretchLastSection(true);
    IME = 2;
    Z_flag = 2;
    N_flag = 2;
    H_flag = 2;
    C_flag = 2;

    // IO
    mnemonicIO
    << "P1"    // 0x00, // Register for reading joy pad info and determining system type (R/W)
    << "SB"    // 0x01, // Serial transfer data (R/W)
    << "SC"    // 0x02, // SIO control (R/W)
    << "unknown"
    << "DIV"   // 0x04, // Divider Register (R/W)
    << "TIMA"  // 0x05, // Timer counter (R/W)
    << "TMA"   // 0x06, // Timer Modulo (R/W)
    << "TAC"   // 0x07, // Timer Control (R/W)
    << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown"
    << "IF"    // 0x0f, // Interrupt Flag (R/W)
    << "NR10"  // 0x10, // Sound Mode 1 register, Sweep register (R/W)
    << "NR11"  // 0x11, // Sound Mode 1 register, Sound length/Wave pattern duty (R/W)
    << "NR12"  // 0x12, // Sound Mode 1 register, Envelope (R/W)
    << "NR13"  // 0x13, // Sound Mode 1 register, Frequency lo (W)
    << "NR14"  // 0x14, // Sound Mode 1 register, Frequency hi (R/W)
    << "unknown"
    << "NR21"  // 0x16, // Sound Mode 2 register, Sound Length; Wave Pattern Duty (R/W) Only bits 7-6 can be read.
    << "NR22"  // 0x17, // Sound Mode 2 register, envelope (R/W)
    << "NR23"  // 0x18, // Sound Mode 2 register, frequency lo data (W)
    << "NR24"  // 0x19, // Sound Mode 2 register, frequency hi data (R/W)
    << "NR30"  // 0x1a, // Sound Mode 3 register, Sound on/off (R/W)
    << "NR31"  // 0x1b, // Sound Mode 3 register, sound length (R/W)
    << "NR32"  // 0x1c, // Sound Mode 3 register, Select output level (R/W)
    << "NR33"  // 0x1d, // Sound Mode 3 register, frequency's lower data (W)
    << "NR34"  // 0x1e, // Sound Mode 3 register, frequency's higher data (R/W)
    << "unknown"
    << "NR41"  // 0x20, // Sound Mode 4 register, sound length (R/W)
    << "NR42"  // 0x21, // Sound Mode 4 register, envelope (R/W)
    << "NR43"  // 0x22, // Sound Mode 4 register, polynomial counter (R/W)
    << "NR44"  // 0x23, // Sound Mode 4 register, counter/consecutive; inital (R/W)
    << "NR50"  // 0x24, // Channel control / ON-OFF / Volume (R/W)
    << "NR51"  // 0x25, // Selection of Sound output terminal (R/W)
    << "NR52"  // 0x26, // Sound on/off (R/W)
    << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown"
    << "WPRAM" // 0x30, // Waveform storage for arbitrary sound data 0xff30 - 0xff3f
    << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown"
    << "unknown" << "unknown" << "unknown" << "unknown" << "unknown" << "unknown"
    << "LCDC"  // 0x40, // LCD Control (R/W)
    << "STAT"  // 0x41, // LCDC Status (R/W)
    << "SCY"   // 0x42, // Scroll Y (R/W)
    << "SCX"   // 0x43, // Scroll X (R/W)
    << "LY"    // 0x44, // LCDC Y-Coordinate (R)
    << "LYC"   // 0x45, // LY Compare (R/W)
    << "DMA"   // 0x46, // DMA Transfer and Start Address (W)
    << "BGP"   // 0x47, // BG & Window Palette Data (R/W)
    << "OBP0"  // 0x48, // Object Palette 0 Data (R/W)
    << "OBP1"  // 0x49, // Object Palette 1 Data (R/W)
    << "WY"    // 0x4a, // Window Y Position (R/W)
    << "WX"    // 0x4b, // Window X Position (R/W)
    ;

    modelIO = new RegisterModel(mnemonicIO, 2);
    ui->tableIO->verticalHeader()->setDefaultSectionSize(rowHeight); //setHeight
    ui->tableIO->setModel(modelIO);
    ui->tableIO->horizontalHeader()->hide();
    ui->tableIO->verticalHeader()->hide();
    ui->tableIO->resizeColumnsToContents();
    ui->tableIO->horizontalHeader()->setStretchLastSection(true);
    // io
    int row_count = modelIO->rowCount();
    for (int i = 0; i < row_count; i++) {
        io[i] = 0xa7;
    }

    // IO
    mnemonicOAM
    << "#01" << "" << "" << ""
    << "#02" << "" << "" << ""
    << "#03" << "" << "" << ""
    << "#04" << "" << "" << ""
    << "#05" << "" << "" << ""
    << "#06" << "" << "" << ""
    << "#07" << "" << "" << ""
    << "#08" << "" << "" << ""
    << "#09" << "" << "" << ""
    << "#10" << "" << "" << ""
    << "#11" << "" << "" << ""
    << "#12" << "" << "" << ""
    << "#13" << "" << "" << ""
    << "#14" << "" << "" << ""
    << "#15" << "" << "" << ""
    << "#16" << "" << "" << ""
    << "#17" << "" << "" << ""
    << "#18" << "" << "" << ""
    << "#19" << "" << "" << ""
    << "#20" << "" << "" << ""
    << "#21" << "" << "" << ""
    << "#22" << "" << "" << ""
    << "#23" << "" << "" << ""
    << "#24" << "" << "" << ""
    << "#25" << "" << "" << ""
    << "#26" << "" << "" << ""
    << "#27" << "" << "" << ""
    << "#28" << "" << "" << ""
    << "#29" << "" << "" << ""
    << "#30" << "" << "" << ""
    << "#31" << "" << "" << ""
    << "#32" << "" << "" << ""
    << "#33" << "" << "" << ""
    << "#34" << "" << "" << ""
    << "#35" << "" << "" << ""
    << "#36" << "" << "" << ""
    << "#37" << "" << "" << ""
    << "#38" << "" << "" << ""
    << "#39" << "" << "" << ""
    << "#40" << "" << "" << ""
    ;

    modelOAM = new RegisterModel(mnemonicOAM, 2);
    ui->tableOAM->verticalHeader()->setDefaultSectionSize(rowHeight); //setHeight
    ui->tableOAM->setModel(modelOAM);
    ui->tableOAM->horizontalHeader()->hide();
    ui->tableOAM->verticalHeader()->hide();
    ui->tableOAM->resizeColumnsToContents();
    ui->tableOAM->horizontalHeader()->setStretchLastSection(true);
    // oam
    row_count = modelOAM->rowCount();
    for (int i = 0; i < row_count; i++) {
        oam[i] = 0xa7;  // random
    }

    color_DEFAULT = QColor(Qt::white);
    color_CHANGED = QColor(Qt::yellow);
    color_PC = QColor(Qt::red);
    color_BP = QColor(Qt::blue);

    cpuA = _cpu->getA();
    cpuBC = _cpu->getBC();
    cpuDE = _cpu->getDE();
    cpuHL = _cpu->getHL();
    cpuSP = _cpu->getSP();
    cpuIME = _cpu->getIME();
    cpuZ = _cpu->getZ();
    cpuN = _cpu->getN();
    cpuH = _cpu->getH();
    cpuC = _cpu->getC();
    memory = _mem->getMemory();
}

void DebuggerWidget::updatePC(unsigned short pc)
{
    QModelIndex index;
    QString newstring;
    newstring = QString("0x%1").arg(pc, 4, 16, QChar('0'));
    int row = modelDisasm->getPcIndex(newstring);
    ui->tableView->selectRow(row);

    // A
    index = modelRegs->index(0, 1, QModelIndex());
    if (A != *cpuA) {
        A = *cpuA;
        newstring = QString("%1").arg(A, 2, 16, QChar('0'));
        modelRegs->setData(index, newstring, Qt::EditRole);
        modelRegs->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelRegs->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // BC
    index = modelRegs->index(1, 1, QModelIndex());
    if (BC != *cpuBC) {
        BC = *cpuBC;
        newstring = QString("%1").arg(BC, 4, 16, QChar('0'));
        modelRegs->setData(index, newstring, Qt::EditRole);
        modelRegs->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelRegs->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // DE
    index = modelRegs->index(2, 1, QModelIndex());
    if (DE != *cpuDE) {
        DE = *cpuDE;
        newstring = QString("%1").arg(DE, 4, 16, QChar('0'));
        modelRegs->setData(index, newstring, Qt::EditRole);
        modelRegs->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelRegs->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // HL
    index = modelRegs->index(3, 1, QModelIndex());
    if (HL != *cpuHL) {
        HL = *cpuHL;
        newstring = QString("%1").arg(HL, 4, 16, QChar('0'));
        modelRegs->setData(index, newstring, Qt::EditRole);
        modelRegs->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelRegs->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // SP
    index = modelRegs->index(4, 1, QModelIndex());
    if (SP != *cpuSP) {
        SP = *cpuSP;
        newstring = QString("%1").arg(SP, 4, 16, QChar('0'));
        modelRegs->setData(index, newstring, Qt::EditRole);
        modelRegs->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelRegs->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // IME
    index = modelFlags->index(0, 1, QModelIndex());
    if (IME != *cpuIME) {
        IME = *cpuIME;
        newstring = QString("%1").arg(IME, 1, 16, QChar('0'));
        modelFlags->setData(index, newstring, Qt::EditRole);
        modelFlags->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelFlags->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // Z
    index = modelFlags->index(1, 1, QModelIndex());
    if (Z_flag != *cpuZ) {
        Z_flag = *cpuZ;
        newstring = QString("%1").arg(Z_flag, 1, 16, QChar('0'));
        modelFlags->setData(index, newstring, Qt::EditRole);
        modelFlags->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelFlags->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // N
    index = modelFlags->index(2, 1, QModelIndex());
    if (N_flag != *cpuN) {
        N_flag = *cpuN;
        newstring = QString("%1").arg(N_flag, 1, 16, QChar('0'));
        modelFlags->setData(index, newstring, Qt::EditRole);
        modelFlags->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelFlags->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // H
    index = modelFlags->index(3, 1, QModelIndex());
    if (H_flag != *cpuH) {
        H_flag = *cpuH;
        newstring = QString("%1").arg(H_flag, 1, 16, QChar('0'));
        modelFlags->setData(index, newstring, Qt::EditRole);
        modelFlags->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelFlags->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // C
    index = modelFlags->index(4, 1, QModelIndex());
    if (C_flag != *cpuC) {
        C_flag = *cpuC;
        newstring = QString("%1").arg(C_flag, 1, 16, QChar('0'));
        modelFlags->setData(index, newstring, Qt::EditRole);
        modelFlags->setData(index, color_CHANGED, Qt::BackgroundRole);
    } else {
        modelFlags->setData(index, color_DEFAULT, Qt::BackgroundRole);
    }

    // io
    int row_count = modelIO->rowCount();
    for (int i = 0; i < row_count; i++) {
        index = modelIO->index(i, 1, QModelIndex());
        if (io[i] != memory[0xff00 + i]) {
            io[i] = memory[0xff00 + i];
            newstring = QString("%1").arg(io[i], 2, 16, QChar('0'));
            modelIO->setData(index, newstring, Qt::EditRole);
            modelIO->setData(index, color_CHANGED, Qt::BackgroundRole);
        } else {
            modelIO->setData(index, color_DEFAULT, Qt::BackgroundRole);
        }
    }

    // oam
    row_count = modelOAM->rowCount();
    for (int i = 0; i < row_count; i++) {
        index = modelOAM->index(i, 1, QModelIndex());
        if (oam[i] != memory[0xfe00 + i]) {
            oam[i] = memory[0xfe00 + i];
            newstring = QString("%1").arg(oam[i], 2, 16, QChar('0'));
            modelOAM->setData(index, newstring, Qt::EditRole);
            modelOAM->setData(index, color_CHANGED, Qt::BackgroundRole);
        } else {
            modelOAM->setData(index, color_DEFAULT, Qt::BackgroundRole);
        }
    }
}

void DebuggerWidget::clicked(const QString text)
{
    if (text == "Step") {
        _dbg->debuggerAction(dbgStep);
    } else if (text == "Next") {
        _dbg->debuggerAction(dbgNext);
    } else if (text == "Run") {
        _dbg->debuggerAction(dbgRun);
    } else if (text == "Break") {
        _dbg->debuggerAction(dbgBreak);
    } else if (text == "Trace") {
        _dbg->debuggerAction(dbgTrace);
    } else if (text == "Reset") {
        _dbg->debuggerAction(dbgReset);
    } else if (text == "NewBP") {
        BreakpointsWidget *b = new BreakpointsWidget();
        b->setDebuggerWidget(this);
        b->setDebugger(_dbg);
        b->update();
        b->show();
    } else if (text == "ToggleBP") {
        QMessageBox::warning(this, tr("Warning"),
                tr("Not Implemented."),
                QMessageBox::Ok);
    }
}

void DebuggerWidget::closeEvent(QCloseEvent *event)
{
    Q_UNUSED(event);
    _dbg->debuggerAction(dbgRun);
    _dbg->enableDebugger(false);
}

void DebuggerWidget::updateBP(unsigned short addr)
{
    QModelIndex index;
    QString newstring;
    newstring = QString("0x%1").arg(addr, 4, 16, QChar('0'));
    int row = modelDisasm->getPcIndex(newstring);
    index = modelDisasm->index(row, 1, QModelIndex());
    modelDisasm->setData(index, Qt::blue, Qt::BackgroundRole);
}
